package com.UnionPayCenter.util;

import com.UnionPayCenter.enums.ErrorCodeEnum;
import com.UnionPayCenter.exception.ApiException;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @program: UnionPayServers
 * @description: 银联商务对接接口
 * @author: bite
 * @create: 2019-05-21 11:09
 **/
@Slf4j
@Component
public class ChinaUmsUtil {
    private static String url;
    @Value("${chinaUMS.apiUrl}")
    public void setUrl(String url) {
        ChinaUmsUtil.url = url;
    }

    private static String msgSrc;//消息来源
    @Value("${chinaUMS.msgSrc}")
    public void setMsgSrc(String msgSrc) {
        ChinaUmsUtil.msgSrc = msgSrc;
    }

    private static String mid;//商户号
    @Value("${chinaUMS.mid}")
    public void setMid(String mid) {
        ChinaUmsUtil.mid = mid;
    }

    private static String tid;//终端号
    @Value("${chinaUMS.tid}")
    public void setTid(String tid) {
        ChinaUmsUtil.tid = tid;
    }

    private static String key;//md5密钥
    @Value("${chinaUMS.key}")
    public void setKey(String key) {
        ChinaUmsUtil.key = key;
    }

    public static JSONObject order(String subOpenId, String merOrderId, String srcReserve, Integer totalAmount){
        try {
            String msgType = "wx.unifiedOrder";//消息类型
            String requestTimestamp = DateFormatUtil.Now();//报文请求时间
            String instMid = "MINIDEFAULT";//机构商户号
            String tradeType = "MINI";//交易类型

            Map<String, String> map = new HashMap<>();
            map.put("msgSrc", ChinaUmsUtil.msgSrc);
            map.put("msgType", msgType);
            map.put("requestTimestamp", requestTimestamp);
            map.put("merOrderId", merOrderId);
            map.put("srcReserve", srcReserve);
            map.put("mid", ChinaUmsUtil.mid);
            map.put("tid", ChinaUmsUtil.tid);
            map.put("instMid", instMid);
            map.put("totalAmount", totalAmount.toString());
            map.put("tradeType", tradeType);
            map.put("subOpenId", subOpenId);

            JSONArray goods = new JSONArray();
            JSONObject good = new JSONObject();
            good.put("good", "充值");
            good.put("quantity", 1);
            good.put("price", totalAmount);

            goods.add(good);
            map.put("goods", goods.toJSONString());
            //生成签名
            String sign = createSign(map);
            map.put("sign", sign);

            HttpClient httpClient = new HttpClient();
            httpClient.setUrl(ChinaUmsUtil.url);
            httpClient.setParams(ChinaUmsUtil.concatHttpRequestParams(map));
            String returnStr = httpClient.post();
            if (!StringUtils.isNullStr(returnStr)) {
                //TODO 结果返回
                JSONObject json = JSONObject.parseObject(returnStr);
                return json;
            } else {
                log.error(String.format("银联下单失败，merOrderId: %s", merOrderId));
                throw new ApiException(ErrorCodeEnum.UP9002);
            }
        } catch (ApiException e) {
            throw e;
        } catch (Exception e) {
            log.error(String.format("银联下单接口请求失败，%s", e.getMessage()), e);
            throw new ApiException(ErrorCodeEnum.UP9003);
        }

    }
    /**
    * @Description:
    * @Param:   merOrderId: 商户订单号
     *          targetOrderId: 支付订单号
     *          srcReserve: 请求系统预留字段
    * @return:
    * @Author: bite
    * @Date: 2019/5/21
    */
    public static JSONObject search(String merOrderId, String targetOrderId, String srcReserve){
        try {
            String msgType = "query";//消息类型
            String requestTimestamp = DateFormatUtil.Now();//报文请求时间
            String instMid = "MINIDEFAULT";//机构商户号
            Map<String, String> map = new HashMap<>();
            map.put("msgSrc", ChinaUmsUtil.msgSrc);
            map.put("msgType", msgType);
            map.put("requestTimestamp", requestTimestamp);
            map.put("srcReserve", srcReserve);
            map.put("mid", ChinaUmsUtil.mid);
            map.put("tid", ChinaUmsUtil.tid);
            map.put("instMid", instMid);
            map.put("merOrderId", merOrderId);
            map.put("targetOrderId", targetOrderId);

            String sign = createSign(map);
            map.put("sign", sign);

            HttpClient httpClient = new HttpClient();
            httpClient.setUrl(ChinaUmsUtil.url);
            httpClient.setParams(ChinaUmsUtil.concatHttpRequestParams(map));
            String returnStr = httpClient.post();
            if (!StringUtils.isNullStr(returnStr)) {
                //TODO 结果返回
                JSONObject json = JSONObject.parseObject(returnStr);
                return json;
            } else {
                log.error(String.format("银联查询失败，merOrderId: %s, targetOrderId: %s", merOrderId, targetOrderId));
                throw new ApiException(ErrorCodeEnum.UP9002);
            }
        }catch (ApiException e){
            throw e;
        }catch (Exception e){
            log.error(String.format("银联查询接口请求失败，%s", e.getMessage()), e);
            throw new ApiException(ErrorCodeEnum.UP9003);
        }
    }

    /** 
    * @Description: 生成签名
    * @Param:  
    * @return:  
    * @Author: bite 
    * @Date: 2019/5/21 
    */ 
    public static String createSign(Map<String, String> parameters) {
        try {
            StringBuffer sb = new StringBuffer();
            Set<Map.Entry<String, String>> entrySet = parameters.entrySet();// 所有参与传参的参数按照accsii排序（升序）
            int count = 0;
            for (Map.Entry<String, String> entry : entrySet) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) {
                    if (count == 0) {
                        sb.append(key + "=" + value);
                        count++;
                    } else {
                        sb.append("&" + key + "=" + value);
                    }
                }
            }
            sb.append(ChinaUmsUtil.key);
            log.info(String.format("银联签名参数: %s", sb.toString()));
            String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase();
            log.info(String.format("银联签名：%s", sign));
            return sign;
        }catch (Exception e){
            log.error(String.format("银联签名生成失败，%s", e.getMessage()), e);
            throw new ApiException(ErrorCodeEnum.UP9001);
        }
    }
    
    /** 
    * @Description: 请求参数转化
    * @Param:  
    * @return:  
    * @Author: bite 
    * @Date: 2019/5/21 
    */ 
    public static String concatHttpRequestParams(Map<String,String> map){
        try {
            StringBuffer sb = new StringBuffer();
            if(map != null){
                int counter = 0;
                Set<Map.Entry<String,String>> entrySet = map.entrySet();
                for(Map.Entry<String,String> entry : entrySet){
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if(counter > 0){
                        if(value != null){
                            sb.append("&").append(key).append("=").append(value);
                        }else{
                            sb.append("&").append(key).append("=");
                        }
                    }else{
                        if(value != null){
                            sb.append(key).append("=").append(value);
                        }else{
                            sb.append(key).append("=");
                        }
                    }
                    counter++;
                }
            }
            log.info(String.format("银联请求参数：%s", sb.toString()));
            return sb.toString();
        }catch (Exception e){
            log.error(String.format("银联请求参数转化失败，%s", e.getMessage()), e);
            throw new ApiException(ErrorCodeEnum.UP9004);
        }
    }

}
